﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
using Library;

namespace DirectoryWeb
{
  /// <summary>
  /// 所属している全グループ画面のフォームです。
  /// </summary>
  public partial class InRoleGroupList : Page
  {
    #region プライベートフィールド
    private DomainObject member;  //メンバー
    private Dictionary<string, DomainGroup> allGroups;  //全グループ(Key:distinguishedName)
    private List<string> addedDistinguishedNames;   //ノードに追加したグループの識別名
    #endregion

    #region イベントハンドラ
    protected void Page_Load(object sender, EventArgs e)
    {
      var name = Request.QueryString["name"];   //名前
      if (String.IsNullOrEmpty(name))
      {
        return;
      }

      CategoryType category;  //Directory オブジェクトの種類
      if (Enum.TryParse<CategoryType>(Request.QueryString["category"], out category) == false)
      {
        return;
      }
      if (this.IsPostBack)
      {
        return;
      }

      switch (category)   //Directory オブジェクトの種類
      {
        case CategoryType.User:
          member = DomainUser.FindByName(name);   //ユーザーを検索
          break;
        case CategoryType.Group:
          member = DomainGroup.FindByName(name);  //グループを検索
          break;
        case CategoryType.Computer:
          member = Computer.FindByName(name);     //コンピューターを検索
          break;
      }
      if (member == null)
      {
        return;
      }

      allGroups = DirectoryAccess.GetGroups<DomainGroup>().ToDictionary(
        group => group.Entry.Properties["distinguishedName"].Value.ToString(), group => group);
      addedDistinguishedNames = new List<string>();

      this.AddChildNode();  //子ノードを追加
      this.GroupListBox.DataSource = CreateGroupTable();  //データソース用のテーブルを作成
      this.GroupListBox.DataTextField = "Text";
      this.GroupListBox.DataValueField = "Value";
      if (addedDistinguishedNames.Count > 1)
      {
        this.GroupListBox.Style.Add(HtmlTextWriterStyle.BorderStyle, "None");
      }
      else
      {
        this.ViewRadioButtonList.Enabled = false;
      }
      this.GroupListBox.DataBind();

      member.Dispose();
      DirectoryAccess.DisposeItems(allGroups.Values);
    }

    protected void ViewRadioButtonList_SelectedIndexChanged(object sender, EventArgs e)
    {
      this.GroupTreeView.Visible = this.ViewRadioButtonList.SelectedIndex == 0;
      this.GroupListBox.Visible = !this.GroupTreeView.Visible;
    }
    #endregion

    #region プライベートメソッド
    /// <summary>
    /// 子ノードを追加します。
    /// </summary>
    private void AddChildNode()
    {
      var node = new TreeNode(member.ToString(), member.Name);
      this.GroupTreeView.Nodes.Add(node);
      if ((member.Category == CategoryType.User) || (member.Category == CategoryType.Computer))
      {
        //プライマリー グループを追加
        var primaryGroupId = (member.Category == CategoryType.User) ?
          ((DomainUser)member).PrimaryGroupId : ((Computer)member).PrimaryGroupId;
        var group = allGroups.Values.Cast<DomainGroup>().Single(grp => grp.Token == primaryGroupId);
        this.AddChildNode(node, group);   //子ノードを追加
      }
      //所属するグループを追加
      foreach (string memberOf in member.Entry.Properties["memberOf"])
      {
        this.AddChildNode(node, allGroups[memberOf]);   //子ノードを追加
      }
    }

    /// <summary>
    /// 子ノードを追加します。
    /// </summary>
    /// <param name="node">子ノードを追加するノード。</param>
    /// <param name="group">子ノードになるグループ。</param>
    private void AddChildNode(TreeNode node, DomainGroup group)
    {
      var displayName = String.Format("{0}（{1}）", group.Name, group.Scope);   //表示するテキスト
      var distinguishedName = group.Entry.Properties["distinguishedName"].Value.ToString();   //識別名
      var childNode = new TreeNode(displayName, group.Name);  //ノードを作成

      node.ChildNodes.Add(childNode);
      if (addedDistinguishedNames.Contains(distinguishedName) == false)
      {
        addedDistinguishedNames.Add(distinguishedName);   //識別名を追加
      }
      //ネストしているグループを追加
      foreach (string memberOf in group.Entry.Properties["memberOf"])
      {
        this.AddChildNode(childNode, allGroups[memberOf]);  //子ノードを追加
      }
    }

    /// <summary>
    /// データソース用のテーブルを作成します。
    /// </summary>
    /// <returns>データソース用のテーブル。</returns>
    private DataTable CreateGroupTable()
    {
      var table = new DataTable();
      table.Columns.Add(new DataColumn("Value", typeof(string)));   //値(distinguishedName)
      table.Columns.Add(new DataColumn("Text", typeof(string)));    //表示するテキスト

      foreach (var distinguishedName in addedDistinguishedNames)
      {
        var row = table.NewRow();
        var group = allGroups[distinguishedName];
        var displayName = String.Format("{0}（{1}）", group.Name, group.Scope);

        row[0] = distinguishedName;
        row[1] = displayName;
        table.Rows.Add(row);
      }
      return table;
    }
    #endregion
  }
}